<template>
  <div class="fx-pagination" :class="[size,{border}]">
    <template v-for="item in layoutComponents" :key="item.key">
      <component :is="item.component" :current-page="currentPage" :total="total" :page-total="pageTotal" :size="size"
                 :page-size="pageSize" :previous-page-show="previousPageShow" :next-page-show="nextPageShow"
                 :pages-arr="pagesArr" :is-more="isMore" @previous-click="previous" @next-click="next"
                 @pages-change="pageTo" @select-change="selectChange" @input-change="inputChange">
        <slot name="previous" v-if="item.key==='prev'">
          <i v-if="!prevText" class="iconfont icon-left fs10"/>
          <span v-else>{{ prevText }}</span>
        </slot>
        <slot name="next" v-if="item.key==='next'">
          <i v-if="!nextText" class="iconfont icon-right fs10"/>
          <span v-else>{{ nextText }}</span>
        </slot>
      </component>
    </template>
  </div>
</template>

<script lang="ts">
import { Component, computed, defineComponent, onMounted, PropType, ref } from 'vue'
import { useModelWatch } from '@/base/hooks'
import { ComponentSize, componentSizeArr } from '@/base/types'
import PaginationTotal from './paginationTotal.vue'
import PaginationPrevious from './paginationPrevious.vue'
import PaginationPages from './paginationPages.vue'
import PaginationNext from './paginationNext.vue'
import PaginationSelect from './paginationSelect.vue'
import PaginationInput from './paginationInput.vue'

interface PaginationProps {
  modelValue: number;
  total: number;
  pageCount: number;
  size: ComponentSize;
  border: boolean;
  pageSize: number | number[];
  layout: string;
  prevText: string;
  nextText: string;
}

export default defineComponent({
  name: 'pagination',
  components: {
    PaginationInput,
    PaginationSelect,
    PaginationNext,
    PaginationPages,
    PaginationPrevious,
    PaginationTotal
  },
  props: {
    modelValue: {
      type: Number as PropType<number>,
      default: 1
    },
    // 总数
    total: {
      type: Number as PropType<number>,
      default: 10
    },
    // 分页个数
    pageCount: {
      type: Number as PropType<number>,
      default: 5
    },
    // 大小
    size: {
      type: String as PropType<ComponentSize>,
      default: 'default',
      validator (val: ComponentSize): boolean {
        return componentSizeArr.includes(val)
      }
    },
    border: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 分页大小
    pageSize: {
      type: [Number, Array] as PropType<number | number[]>,
      default: 10
    },
    // 展示数据列表
    layout: {
      type: String as PropType<string>,
      default: 'prev,pager,next',
      validator (val: string): boolean {
        const layoutArr = val.split(',')
        return layoutArr.every((item: string) => {
          return ['prev', 'pager', 'next', 'sizes', 'jumper', 'total'].includes(item.trim())
        })
      }
    },
    // 上一页文字
    prevText: {
      type: String as PropType<string>,
      default: null
    },
    // 下一页文字
    nextText: {
      type: String as PropType<string>,
      default: null
    },
    // 是否显示更多按钮
    isMore: {
      type: Boolean as PropType<boolean>,
      default: true
    }
  },
  setup (props: PaginationProps) {
    // 当前页
    const currentPage = ref<number>(props.modelValue)
    useModelWatch(() => props.modelValue, currentPage)
    // 当前分页大小
    const currentPageSize = ref<number>(10)
    // 布局数组
    const layoutComponents = computed(() => {
      const layout = props.layout.split(',').filter((item: string) => item !== '')
      const components: { [key: string]: Component } = {
        prev: PaginationPrevious,
        pager: PaginationPages,
        next: PaginationNext,
        jumper: PaginationInput,
        total: PaginationTotal,
        sizes: PaginationSelect
      }
      return layout.map((item: string) => {
        return {
          key: item.trim(),
          component: components[item.trim()]
        }
      })
    })
    // 分页页数总量
    const pageTotal = computed<number>(() => Math.ceil(props.total / currentPageSize.value))
    // 显示more 上一页
    const previousPageShow = computed<boolean>(() => {
      const count: number = props.pageCount % 2 === 1 ? props.pageCount : props.pageCount + 1
      const startPage: number = currentPage.value - (count - 1) / 2
      return startPage > 1 && pageTotal.value > pagesArr.value.length
    })
    // 显示more 下一页
    const nextPageShow = computed<boolean>(() => {
      const count: number = props.pageCount % 2 === 1 ? props.pageCount : props.pageCount + 1
      const endPage: number = currentPage.value + (count - 1) / 2
      return endPage < pageTotal.value && pageTotal.value > pagesArr.value.length
    })
    // 分页中间间隔
    const pagesArr = computed<number[]>(() => {
      const array: number[] = []
      let count: number = props.pageCount % 2 === 1 ? props.pageCount : props.pageCount + 1
      if (pageTotal.value < count) count = pageTotal.value
      let startPage: number = currentPage.value - (count - 1) / 2
      let endPage: number = currentPage.value + (count - 1) / 2
      if (startPage < 1) {
        endPage = endPage + (1 - startPage)
        startPage = 1
      }
      if (endPage > pageTotal.value) {
        startPage = startPage - (endPage - pageTotal.value)
        endPage = pageTotal.value
      }
      for (let i = startPage; i <= endPage; i++) {
        array.push(i)
      }
      return array
    })

    const pageTo = (page: number): void => {
      currentPage.value = page
    }
    const previous = (): void => {
      currentPage.value--
      if (currentPage.value <= 1) currentPage.value = 1
    }
    const next = (): void => {
      currentPage.value++
      if (currentPage.value >= pageTotal.value) currentPage.value = pageTotal.value
    }
    const selectChange = (page: number): void => {
      currentPageSize.value = page
      currentPage.value = 1
    }
    const inputChange = (page: number): void => {
      currentPage.value = page
    }

    onMounted(() => {
      if (props.pageSize instanceof Array && props.pageSize.length) {
        currentPageSize.value = props.pageSize[0]
      } else if (!(props.pageSize instanceof Array)) {
        currentPageSize.value = props.pageSize
      }
    })

    return {
      pagesArr,
      currentPage,
      previousPageShow,
      nextPageShow,
      currentPageSize,
      pageTotal,
      layoutComponents,
      pageTo,
      previous,
      next,
      selectChange,
      inputChange
    }
  }
})
</script>
